/*
 * Copyright (c) 2012 Universidad Antonio de Nebrija.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0
 * which accompanies this distribution, and is available at
 * http://www.apache.org/licenses/LICENSE-2.0.html
 * 
 * Contributors:
 *    Universidad Antonio de Nebrija - initial API, implementation and documentation
 */
package com.nebrija.riif.model;

import java.util.ArrayList;
import java.util.Set;

/**
 * A list of ChildComponentUnits e.g. MEMORY[1:N]
 * @author asanchep
 *
 */
public class ChildComponentList implements ChildComponent {

	/** Name of the list */
	protected String name;
	/** Component implemented by every child in the list */
	private Component implementedComponent;
	/** Component where this child component resides*/
	private Component container;
	/** List with the ChildComponentUnits*/
	private ArrayList<ChildComponentUnit> childs = new ArrayList<ChildComponentUnit>();
	/** If the array size depends on a constant [1:N], it stores the constant name N*/
	private String constantDependantSize;
	
	/**
	 * Creates a ChildComponentList
	 * @param name name of the child component
	 * @param container Component where it resides
	 * @param element Type of component that this child belongs to, represented by the component itself
	 * @param indexes String with the information of the indices. E.g. [1:9] or [1:N]
	 */
	public ChildComponentList(String name, Component container, Component element, String indexes) {
		this(name, container, element, ChildComponentList.parseIndexes(indexes, container));
		constantDependantSize=ChildComponentList.isSizeDependingOnConstant(indexes);
	}
	
	/**
	 * Creates a ChildComponentList
	 * @param name name of the child component
	 * @param container Component where it resides
	 * @param element Type of component that this child belongs to, represented by the component itself
	 * @param size number of ChildComponent elements included in the list
	 */
	public ChildComponentList(String name, Component container, Component element, int size) {
		this.implementedComponent=element;
		this.name=name;
		this.container=container;
		// Creating the individual elements and adding them to the list.
		// We create them as we might want to modify one of them independently
		for(int i=0;i<size;i++){
			ChildComponentUnit ccu = new ChildComponentUnit(name, container, implementedComponent);
			childs.add(ccu);
		}
	}	

	@Override
	public String getName() {
		return name;
	}

	/**
	 * Parse a string containing information of the size. E.g. [1:10] or [1:N]
	 * @param indexes the string with the information
	 * @param container the container where the child component is included to locate possible external references 
	 * @return an integer with the size or -1 if the string cannot be processed
	 */
	protected static int parseIndexes(String indexes, Component container){
		// Removing the [ and ] characters
		indexes = indexes.replaceAll("\\[", "").replaceAll("\\]", "");
		//Looking for the : character in 1:10 or 1:N 
		int indexOfColon = indexes.indexOf(":");
		if (indexOfColon==-1){
			return indexOfColon;
		}
		// Getting the value after the : character. E.g. 10 or N
		String value = indexes.substring(indexOfColon+1);
		int size = -1;
		try{
			// If it is an integer, return the value, e.g. 10
			size = Integer.parseInt(value);
			return size;
		}catch(NumberFormatException e){
			// It is not an integer, it should be a reference to a constant
		}
		
		try{ 
			// Looking for the constant and checking that the value is an integer
			size = (Integer)Util.resolveConstant(value, container);
		}catch(ClassCastException cce){
		}
		return size;
	}
	
	/**
	 * Checks if the size depends on an external constant
	 * @param indexes the string with the information of the size e.g. [1:10] or [1:N]
	 * @return a string with the constant name (N) or null if it does not depend on a constant 
	 */
	protected static String isSizeDependingOnConstant(String indexes){
		String res=null;
		// Removing the [ and ] characters
		indexes = indexes.replaceAll("\\[", "").replaceAll("\\]", "");
		//Looking for the : character in 1:10 or 1:N 
		int indexOfColon = indexes.indexOf(":");
		if (indexOfColon==-1){
			return res;
		}
		// Getting the value after the : character. E.g. 10 or N
		String value = indexes.substring(indexOfColon+1);
		try{
			//Checking if it is an integer
			Integer.parseInt(value);
		}catch(NumberFormatException e){
			//If it is not an integer, let's return the string after the : character
			res=value;
		}
		return res;
		
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("\n--------[Child Array]---------\n");
		for(ChildComponentUnit child: childs){
			sb.append(child.toString());
		}
		sb.append("---------[/Child Array]-----------\n");
		return sb.toString();
	}

	public Component getContainer() {
		return container;
	}

	@Override
	public void setProperty(String element, String property, Object value) {
		// We only set a property if it existed in the component that this child is type of
		if(!implementedComponent.existElement(element)){
			return;
		}	
		for(int i=0;i<childs.size();i++){
			childs.get(i).setProperty(element, property, value);
		}
	}

	@Override
	public void resolve(RIIFElement container) {
		//propagate to the units
		for(ChildComponentUnit child: childs){
			child.resolve(container);
		}
	}	

	@Override
	public void clear(RIIFElement container) {
		//propagate to the units
		for(ChildComponentUnit child: childs){
			child.clear(container);
		}
	}		
	
	/**
	 * Retrieves a specific child component of the list
	 * @param i the position in the list
	 * @return the child component corresponding to that position or null if no component is found
	 */
	public ChildComponentUnit getChild(int i){
		return childs.get(i); 
	}

	public String getConstantDependantSize() {
		return constantDependantSize;
	}
	
	
	public String getImplementedComponentName(){
		return implementedComponent.getName();
	}
	
	/**
	 * Count of the child components
	 * @return an integer with the number of ChildComponentUnits in the list
	 */
	public int getChildCount(){
		return childs.size();
	}

	@Override
	public RIIFElement getElement(String name) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Set<String> getElementNames() {
		return null;
	}
}
